package com.ybzl.common.config.minio;

import com.ybzl.common.utils.DateUtils;
import com.ybzl.common.utils.file.FileUtils;
import com.ybzl.common.utils.spring.ApplicationContextHolder;
import io.minio.Result;
import io.minio.messages.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @description: miniio工具类:
 * 1、上传文件时会自动创建桶
 * 2、静态变量是全局共享的（实例和类级别共享）
 * @author: 233
 * @create: 2021-08-06 09:16
 **/
public class MinioUtil {

    private static final Logger logger = LoggerFactory.getLogger(MinioUtil.class);
    private static final MinioPool minioPool = ApplicationContextHolder.getBean(MinioPool.class);
    private static final MinioConfig config = ApplicationContextHolder.getBean(MinioConfig.class);

    /**
     * 校验桶
     *
     * @param bucketName 桶名
     * @return boolean
     */
    public static boolean checkBucket(String bucketName) {
        try {
            MinioConn conn = minioPool.borrowObject();
            boolean at = conn.getMinioClient().bucketExists(bucketName);
            minioPool.returnObject(conn);
            return at;
        } catch (Exception e) {
            logger.error("{}", e.getMessage(), e);
        }
        return false;
    }

    /**
     * 创建桶
     *
     * @param bucketName 桶名
     */
    public static void create(String bucketName) {
        try {
            if (!checkBucket(bucketName)) {
                MinioConn conn = minioPool.borrowObject();
                conn.getMinioClient().makeBucket(bucketName);
                minioPool.returnObject(conn);
            }
        } catch (Exception e) {
            logger.error("{}", e.getMessage(), e);
        }
    }

    /**
     * 删除桶
     *
     * @param bucketName 桶名
     */
    public static void delete(String bucketName, String objectName) {
        try {
            MinioConn conn = minioPool.borrowObject();
            conn.getMinioClient().removeObject(bucketName, objectName);
            minioPool.returnObject(conn);
        } catch (Exception e) {
            logger.error("{}", e.getMessage(), e);
        }
    }

    /**
     * 根据桶查询文件列表
     *
     * @param bucketName 桶名
     * @return files
     */
    public static List<String> listObject(String bucketName) {
        List<String> list = new ArrayList<>();
        Iterable<Result<Item>> objs = null;
        try {
            MinioConn conn = minioPool.borrowObject();
            objs = conn.getMinioClient().listObjects(bucketName);
            minioPool.returnObject(conn);
        } catch (XmlPullParserException e) {
            logger.error("{}", e.getMessage(), e);
        } catch (Exception e) {
            logger.error("{}", e.getMessage(), e);
        }
        for (Result<Item> tmp : objs) {
            try {
                list.add(tmp.get().objectName());
            } catch (Exception e) {
                logger.error("{}", e.getMessage(), e);
            }
        }

        return list;
    }

    /**
     * 单个文件上传
     * 1.当文件名中包含了目录类型时，会在桶下创建对应的文件夹（可用于业务上非结构化数据的区分）
     *
     * @param bizFolder  业务文件夹
     * @param file       上传文件
     */
    public static String upload(String bizFolder, MultipartFile file) {
        try {
            // 文件名
            String fileName = FileUtils.mainName(file.getOriginalFilename());
            // 扩展名
            String extName = FileUtils.extName(file.getOriginalFilename());

            String newName = "";

            newName = fileName + "_" + DateUtils.dateTimeNow().substring(4) + "." + extName;

            /*if (!ObjectUtils.isEmpty(extName)) {
                // 防止同名文件被覆盖
                newName = fileName + "_" + DateUtils.dateTimeNow().substring(4) + "." + extName;

            }else{
                // 防止同名文件被覆盖
                newName = fileName + "_" + DateUtils.dateTimeNow().substring(4);
            }*/

            if (!ObjectUtils.isEmpty(bizFolder)) {
                newName = bizFolder + "/" + newName;
            }
            return upload(config.getBucketName(), newName, file.getInputStream(), file.getSize(), file.getContentType());

        } catch (Exception e) {
            logger.error("{}", e.getMessage(), e);
        }

        return null;
    }

    /**
     * 上传文件，并返回文件路径
     *
     * @param bucketName  桶名
     * @param fileName    文件名
     * @param inputStream 文件数据流
     * @param fileSize    文件大小
     * @param contentType 文件类型
     */
    public static String upload(String bucketName, String fileName, InputStream inputStream, Long fileSize, String contentType) {
        try {
            MinioConn conn = minioPool.borrowObject();
            conn.getMinioClient().putObject(bucketName, fileName, inputStream, fileSize, contentType);
            String pathUrl = conn.getMinioClient().getObjectUrl(bucketName, fileName);
            minioPool.returnObject(conn);
            return URLDecoder.decode(pathUrl.substring(pathUrl.indexOf(bucketName) - 1), StandardCharsets.UTF_8.name());
        } catch (Exception e) {
            logger.error("upload error:{}", e.getMessage(), e);
        } finally {
            if (null != inputStream) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    logger.error("{}", e.getMessage(), e);
                }
            }
        }
        return "";
    }

    /**
     * 获取文件流
     *
     * @param bucketName 桶名
     * @param objectName 文件名
     * @return 文件流
     */
    public static InputStream getObj(String bucketName, String objectName) {
        InputStream is = null;
        try {
            MinioConn conn = minioPool.borrowObject();
            is = conn.getMinioClient().getObject(bucketName, objectName);
            minioPool.returnObject(conn);
            return is;
        } catch (Exception e) {
            logger.error("{}", e.getMessage(), e);
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    logger.error("{}", e.getMessage(), e);
                }
            }
        }

        return null;
    }
}
